﻿using Cuofrisp.Core;
using Cuofrisp.Core.ParallelCore.Interfaces;
using Cuofrisp.Core.ParallelCore.Tools;
using MathNet.Symbolics;

namespace Cuofrisp.Console.MetricInverseProviders
{
    internal sealed class DiagonalMetricInverseProvider : IMetricInverseProvider
    {
        private static bool IsJustZero(SymbolicExpression expression)
        {
            return expression.Type is SymbolicExpressionType.RationalNumber &&
                expression.RationalNumberValue.IsZero;
        }

        public void TrySetMetricInverse(
            CuofrispResult result, IExpressionSimplifier simplifier, out bool isNotFullRank)
        {
            bool isNotDiagonal = false;
            bool isNotFullRankInner = false;

            _ = Parallel.For(0, result.MetricInverse.Length,
                new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
                (iJ, state) => {
                    var (i, j) = iJ.As2dIndex(result.VariableCount);
                    var value = result.Metric[i, j];
                    if (i == j)
                    {
                        if (IsJustZero(value))
                        {
                            isNotFullRankInner = true;
                            state.Stop();
                            return;
                        }
                        result.MetricInverse[i, j] = 1 / value;
                    }
                    else
                    {
                        if (!IsJustZero(value))
                        {
                            isNotDiagonal = true;
                            state.Stop();
                            return;
                        }
                        result.MetricInverse[i, j] = value;
                    }
                });

            if (isNotDiagonal)
            {
                throw new NotSupportedException(
                    "不可以使用此求逆器（diagonal）求逆，因为给定的矩阵不是对角矩阵。");
            }
            isNotFullRank = isNotFullRankInner;
        }
    }
}
